// only support Windows
#ifdef _WIN64
#include <Windows.h>
#else
#error "do linux or macos support latter"
#endif // OS platform support
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <thread>
#include <cmath>
#include <chrono>
// third party
#define MSF_GIF_IMPL
#include "msf_gif.h"

// ------------------------------------------------

static HWND hOverlayWnd = NULL;
static int selectStartX = 0;
static int selectStartY = 0;
static int selectEndX = 0;
static int selectEndY = 0;
static bool isSelecting = false;
static bool selectionConfirmed = false;

// ------------------------------------------------

struct Config {
    bool fullscreen = true;
    int regionX = 0;
    int regionY = 0;
    int regionWidth = 0;
    int regionHeight = 0;
    int fps = 10;
    int duration = 3; // seconds
    std::string output = "recording.gif";
    int delay = 0;
    bool useSelectedRegion = false;
};

// 捕获屏幕区域并转换为RGBA格式
bool captureScreenRegion(int x, int y, int width, int height, std::vector<uint8_t> &rgbaData) {
    #ifdef _WIN64
    HDC hdcScreen = GetDC(NULL);
    HDC hdcMemDC = CreateCompatibleDC(hdcScreen);

    HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, width, height);
    HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdcMemDC, hBitmap);

    // 捕获屏幕区域
    BitBlt(hdcMemDC, 0, 0, width, height, hdcScreen, x, y, SRCCOPY);
    // 获取位图信息(RGBA格式)
    BITMAPINFOHEADER bmpInfoHeader = {0};
    bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmpInfoHeader.biWidth = width;
    bmpInfoHeader.biHeight = height;
    bmpInfoHeader.biPlanes = 1;
    bmpInfoHeader.biBitCount = 32;
    bmpInfoHeader.biCompression = BI_RGB;
    bmpInfoHeader.biSizeImage = 0;
    bmpInfoHeader.biXPelsPerMeter = 0;
    bmpInfoHeader.biYPelsPerMeter = 0;
    bmpInfoHeader.biClrUsed = 0;

    // 获取位图数据
    rgbaData.resize(width * height * 4);
    GetDIBits(hdcMemDC, hBitmap, 0, height, rgbaData.data(), (BITMAPINFO *)&bmpInfoHeader, DIB_RGB_COLORS);

    // 清理资源
    SelectObject(hdcMemDC, hOldBitmap);
    DeleteObject(hBitmap);
    DeleteDC(hdcMemDC);
    ReleaseDC(NULL, hdcScreen);

    return true;
    #else // Linux / MacOs
    #error "Not define yet"
    return false;
    #endif // OS Platform 

}

// 鼠标选择区域的回调函数(Windows)
#ifdef _WIN64
LRESULT CALLBACK OverlayWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
        case WM_LBUTTONDOWN: {
            selectStartX = LOWORD(lParam);
            selectStartY = HIWORD(lParam);
            selectEndX = selectStartX;
            selectEndY = selectStartY;
            isSelecting = true;
            return 0;
        }
        case WM_MOUSEMOVE: {
            if (isSelecting) {
                selectEndX = LOWORD(lParam);
                selectEndY = HIWORD(lParam);
                InvalidateRect(hWnd, NULL, TRUE);
            }
            return 0;
        }
        case WM_LBUTTONUP: {
            if (isSelecting) {
                selectEndX = LOWORD(lParam);
                selectEndY = HIWORD(lParam);
                isSelecting = false;
                selectionConfirmed = true;
                PostMessage(hWnd, WM_CLOSE, 0, 0);
            }
            return 0;
        }
        case WM_PAINT: {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            
            // 绘制半透明遮罩
            HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 0));
            HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
            SetBkColor(hdc, RGB(0, 0, 0));
            SetTextColor(hdc, RGB(255, 255, 255));
            
            // 计算选择区域
            int x1 = std::min(selectStartX, selectEndX);
            int y1 = std::min(selectStartY, selectEndY);
            int x2 = std::max(selectStartX, selectEndX);
            int y2 = std::max(selectStartY, selectEndY);
            
            // 绘制遮罩（除选择区域外）
            RECT rect;
            GetClientRect(hWnd, &rect);
            
            // 上
            rect.bottom = y1;
            FillRect(hdc, &rect, hBrush);
            // 下
            rect.top = y2;
            rect.bottom = GetSystemMetrics(SM_CYSCREEN);
            FillRect(hdc, &rect, hBrush);
            // 左
            rect.top = y1;
            rect.bottom = y2;
            rect.right = x1;
            FillRect(hdc, &rect, hBrush);
            // 右
            rect.left = x2;
            rect.right = GetSystemMetrics(SM_CXSCREEN);
            FillRect(hdc, &rect, hBrush);
            
            // 绘制选择框
            HPEN hPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
            HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
            Rectangle(hdc, x1, y1, x2, y2);
            
            // 显示区域尺寸
            char sizeText[256];
            sprintf_s(sizeText, "%dx%d", x2 - x1, y2 - y1);
            TextOutA(hdc, x1 + 5, y1 + 5, sizeText, strlen(sizeText));
            
            // 清理资源
            SelectObject(hdc, hOldPen);
            DeleteObject(hPen);
            SelectObject(hdc, hOldBrush);
            DeleteObject(hBrush);
            EndPaint(hWnd, &ps);
            return 0;
        }
        case WM_DESTROY:
            return 0;
        default:
            return DefWindowProc(hWnd, msg, wParam, lParam);
    }
}
#endif

// 鼠标选择区域功能(Windows实现)
#ifdef _WIN64
// todo: failed to select region
bool selectRegion(int& x, int& y, int& width, int& height) {
    // 注册窗口类
    const char* className = "ScreenRegionSelector";
    WNDCLASSEX wc = {0};
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.lpfnWndProc = OverlayWndProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.hCursor = LoadCursor(NULL, IDC_CROSS);
    wc.lpszClassName = className;
    
    if (!RegisterClassEx(&wc)) {
        std::cerr << "无法注册窗口类" << std::endl;
        return false;
    }
    
    // 创建全屏透明窗口
    hOverlayWnd = CreateWindowEx(
        WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TRANSPARENT,
        className,
        "区域选择",
        WS_POPUP,
        0, 0,
        GetSystemMetrics(SM_CXSCREEN),
        GetSystemMetrics(SM_CYSCREEN),
        NULL,
        NULL,
        GetModuleHandle(NULL),
        NULL
    );
    
    if (!hOverlayWnd) {
        std::cerr << "无法创建窗口" << std::endl;
        UnregisterClass(className, GetModuleHandle(NULL));
        return false;
    }
    
    // 设置窗口透明度(50%)
    SetLayeredWindowAttributes(hOverlayWnd, 0, 128, LWA_ALPHA);
    
    // 显示窗口
    ShowWindow(hOverlayWnd, SW_SHOW);
    UpdateWindow(hOverlayWnd);
    
    std::cout << "请用鼠标拖动选择录制区域，松开鼠标确认" << std::endl;
    
    // 消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0) && !selectionConfirmed) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    
    // 计算选择区域
    x = std::min(selectStartX, selectEndX);
    y = std::min(selectStartY, selectEndY);
    width = std::abs(selectEndX - selectStartX);
    height = std::abs(selectEndY - selectStartY);
    
    // 验证区域有效性
    if (width <= 0 || height <= 0) {
        std::cerr << "无效的选择区域" << std::endl;
        return false;
    }
    
    // 清理
    DestroyWindow(hOverlayWnd);
    UnregisterClass(className, GetModuleHandle(NULL));
    return true;
}
#else
// 鼠标选择区域功能(Linux实现，预留)
bool selectRegion(int& x, int& y, int& width, int& height) {
    std::cerr << "Linux平台鼠标选择区域功能尚未实现" << std::endl;
    return false;
}
#endif



// 显示使用帮助
void showUsage() {
    std::cout << "GIF屏幕录制工具 - 使用msf_gif库实现" << std::endl;
    std::cout << "----------------------------------------" << std::endl;
    std::cout << "用法: gif-rec [选项]" << std::endl;
    std::cout << std::endl;
    std::cout << "选项:" << std::endl;
    std::cout << "  -h, --help            显示此帮助信息" << std::endl;
    std::cout << "  -f, --fps <数值>      设置录制帧率 (默认: 10)" << std::endl;
    std::cout << "  -d, --duration <秒>   设置录制时长 (默认: 3秒)" << std::endl;
    std::cout << "  -o, --output <文件>   设置输出文件名 (默认: recording.gif)" << std::endl;
    std::cout << "  -s, --select          使用鼠标选择录制区域(默认: 全屏录制)" << std::endl;
    std::cout << "  --delay <秒>          开始录制前的延迟时间 (默认: 0)" << std::endl;
    std::cout << std::endl;
    std::cout << "示例:" << std::endl;
    std::cout << "  gif-rec -f 15 -d 5 -o animation.gif   以15fps录制5秒的全屏GIF" << std::endl;
    std::cout << "  gif-rec -s -f 20 -d 10                鼠标选择区域，以20fps录制10秒" << std::endl;
    std::cout << "  gif-rec --delay 3 -o demo.gif         延迟3秒后开始全屏录制" << std::endl;
}

// 解析命令行参数
bool parseCommandLine(int argc, char* argv[], Config& config) {
    for (int i = 1; i < argc; ++i) {
        std::string arg = argv[i];
        
        if (arg == "-h" || arg == "--help") {
            showUsage();
            return false;
        }
        else if (arg == "-f" || arg == "--fps") {
            if (i + 1 < argc) {
                config.fps = std::stoi(argv[++i]);
                if (config.fps <= 0 || config.fps > 60) {
                    std::cerr << "错误: FPS必须在1-60之间" << std::endl;
                    return false;
                }
            }
            else {
                std::cerr << "错误: " << arg << "选项需要一个参数" << std::endl;
                return false;
            }
        }
        else if (arg == "-d" || arg == "--duration") {
            if (i + 1 < argc) {
                config.duration = std::stoi(argv[++i]);
                if (config.duration <= 0) {
                    std::cerr << "错误: 录制时长必须大于0" << std::endl;
                    return false;
                }
            }
            else {
                std::cerr << "错误: " << arg << "选项需要一个参数" << std::endl;
                return false;
            }
        }
        else if (arg == "-o" || arg == "--output") {
            if (i + 1 < argc) {
                config.output = argv[++i];
            }
            else {
                std::cerr << "错误: " << arg << "选项需要一个参数" << std::endl;
                return false;
            }
        }
        else if (arg == "-s" || arg == "--select") {
            config.useSelectedRegion = true;
            config.fullscreen = false;
        }
        else if (arg == "--delay") {
            if (i + 1 < argc) {
                config.delay = std::stoi(argv[++i]);
                if (config.delay < 0) {
                    std::cerr << "错误: 延迟时间不能为负数" << std::endl;
                    return false;
                }
            }
            else {
                std::cerr << "错误: " << arg << "选项需要一个参数" << std::endl;
                return false;
            }
        }
        else {
            std::cerr << "错误: 未知选项 " << arg << std::endl;
            showUsage();
            return false;
        }
    }
    
    // 全屏模式下获取屏幕尺寸
    if (config.fullscreen) {
#ifdef _WIN64
        config.regionWidth = GetSystemMetrics(SM_CXSCREEN);
        config.regionHeight = GetSystemMetrics(SM_CYSCREEN);
#else
        // Linux平台屏幕尺寸获取（预留）
        std::cerr << "Linux平台全屏尺寸获取尚未实现" << std::endl;
        return false;
#endif
    }
    
    return true;
}


// 翻转RGBA图像数据（将底到顶转为顶到下）
void flipImageVertically(std::vector<uint8_t>& rgbaData, int width, int height) {
    int rowSize = width * 4; // 每行的字节数（RGBA格式，4字节/像素）
    // 交换上下对称的行
    for (int y = 0; y < height / 2; ++y) {
        int topRow = y;
        int bottomRow = height - 1 - y;
        // 交换两行数据
        std::swap_ranges(
            rgbaData.begin() + topRow * rowSize,
            rgbaData.begin() + (topRow + 1) * rowSize,
            rgbaData.begin() + bottomRow * rowSize
        );
    }
}

// 录制GIF
bool recordGif(const Config& config) {
    int x = 0;
    int y = 0;
    int width = config.regionWidth;
    int height = config.regionHeight;
    
    // 鼠标选择区域
    if (config.useSelectedRegion) {
        if (!selectRegion(x, y, width, height)) {
            std::cerr << "错误: 无法选择录制区域" << std::endl;
            return false;
        }
    }
    
    // 延迟开始录制
    if (config.delay > 0) {
        std::cout << "录制将在 " << config.delay << " 秒后开始..." << std::endl;
        for (int i = config.delay; i > 0; --i) {
            std::cout << "\r倒计时: " << i << " 秒" << std::flush;
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
        std::cout << std::endl;
    }
    
    // 显示录制信息
    std::cout << "开始录制GIF..." << std::endl;
    std::cout << "区域: " << x << ", " << y << " 尺寸: " << width << "x" << height << std::endl;
    std::cout << "帧率: " << config.fps << "fps  时长: " << config.duration << "秒" << std::endl;
    std::cout << "输出文件: " << config.output << std::endl;
    
    // 初始化GIF编码器
 // 初始化GIF编码器
    MsfGifState gifState = {};
    msf_gif_begin(&gifState, width, height);
    
    // 设置BGRA标志(Windows默认捕获格式)
    msf_gif_bgra_flag = true;
    
    // 计算总帧数和每帧延迟(百分之一秒)
    int totalFrames = config.fps * config.duration;
    int centisecondsPerFrame = 100 / config.fps; // 每帧延迟(百分之一秒)
    
    std::vector<uint8_t> frameData;
    
    // 开始录制
    for (int frame = 0; frame < totalFrames; ++frame) {
        auto startTime = std::chrono::high_resolution_clock::now();
        
        // 捕获当前帧
        if (!captureScreenRegion(x, y, width, height, frameData)) {
            std::cerr << "错误: 无法捕获屏幕" << std::endl;
            msf_gif_end(&gifState);
            return false;
        }
        
        // 翻转图像数据(解决上下颠倒问题)
        flipImageVertically(frameData, width, height);
        
        // 添加帧到GIF
        msf_gif_frame(&gifState, frameData.data(), centisecondsPerFrame, 8, width * 4);
        
        // 显示进度
        std::cout << "\r录制进度: " << (frame + 1) << "/" << totalFrames << " 帧" << std::flush;
        
        // 控制帧率
        auto endTime = std::chrono::high_resolution_clock::now();
        auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
        
        if (elapsed < (1000 / config.fps)) {
            std::this_thread::sleep_for(std::chrono::milliseconds((1000 / config.fps) - elapsed));
        }
    }
    
    std::cout << std::endl;
    
    // 结束GIF生成
    MsfGifResult result = msf_gif_end(&gifState);
    
    // 保存GIF文件
    if (result.data) {
        FILE* fp = fopen(config.output.c_str(), "wb");
        if (fp) {
            fwrite(result.data, result.dataSize, 1, fp);
            fclose(fp);
            std::cout << "GIF录制完成! 文件大小: " << result.dataSize << " 字节" << std::endl;
        } else {
            std::cerr << "错误: 无法打开输出文件" << std::endl;
            msf_gif_free(result);
            return false;
        }
    } else {
        std::cerr << "错误: 生成GIF失败" << std::endl;
        return false;
    }
    
    // 释放资源
    msf_gif_free(result);
    
    return true;
}

int main(int argc, char* argv[]) {
    #if _WIN64
    // 启用DPI感知
    SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
    #endif
    Config config;

    // 解析命令行参数
    if (!parseCommandLine(argc, argv, config)) {
        return 1;
    }
     // 录制GIF
    if (!recordGif(config)) {
        return 1;
    }
    return 0;
}